package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.comment.service.CommentHotService;
import com.heima.comment.service.CommentService;
import com.heima.comment.service.TextReviewsService;
import com.heima.common.article.HotArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.UserFeign;
import com.heima.model.comment.dtos.CommentDTO;
import com.heima.model.comment.dtos.CommentLikeDTO;
import com.heima.model.comment.dtos.CommentSaveDTO;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vo.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.app.dtos.NewBehaviorDTO;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author huan
 * @serial 每天一百行, 致敬未来的自己
 * @Description
 */
@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Autowired
    UserFeign userFeign;
    @Autowired
    ArticleFeign articleFeign;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    TextReviewsService textReviewsService;
    @Autowired
    RedissonClient redisson;
    @Autowired
    CommentHotService commentHotService;
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Override
    public ResponseResult saveComment(CommentSaveDTO dto) {
        //校验用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //DFA敏感词筛选,用**覆盖
        String textScan = textReviewsService.handleSensitive(dto.getContent());
        //阿里云校验评论内容是否违规,将违规内容用*覆盖
        String textContent = textReviewsService.handleTextScan((textScan));
        //远程查询当前登陆用户信息
        ResponseResult<ApUser> result = userFeign.findUserById(user.getId());
        if (!result.checkCode()) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        user = result.getData();
        //远程查询文章接口
        ResponseResult<Integer> article = articleFeign.findChannelIdByArticleId(dto.getArticleId());
        if (!article.checkCode()) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        //获取文章对应的频道ID
        Integer channelId = article.getData();
        //构建评论对象
        ApComment comment = ApComment.builder().articleId(dto.getArticleId()).content(textContent)
                .authorId(user.getId()).authorName(user.getName()).type((short) 0)
                .channelId(channelId).image(user.getImage()).likes(0).reply(0).flag((short) 0)
                .createdTime(new Date())
                .updatedTime(new Date()).build();
        mongoTemplate.save(comment);
        //MQ发送评论行为消息
        NewBehaviorDTO mess = new NewBehaviorDTO();
        mess.setType(NewBehaviorDTO.BehaviorType.COMMENT);
        mess.setArticleId(dto.getArticleId());
        mess.setAdd(1);
        rabbitTemplate.convertAndSend(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_QUEUE, JSON.toJSONString(mess));
        log.info("评论行为 发送消息 ==>{}", JSON.toJSONString(mess));

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult saveCommentLike(CommentLikeDTO dto) {
        //1 参数检查 (Validated校验)
        //2 判断用户登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        RLock lock = redisson.getLock("likes-lock");
        lock.lock();
        ApComment apComment;
        try {
            //3 查询评论
            apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
            if (apComment == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
            }
            // 用户不能重复点赞
            ApCommentLike apCommentLike = mongoTemplate.findOne(
                    Query.query(Criteria.where("authorId").is(user.getId())
                            .and("commentId").is(dto.getCommentId())
                    ),
                    ApCommentLike.class);
            Short operation = dto.getOperation();
            if (apCommentLike != null && operation.intValue() == 0) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "已点赞");
            }
            //点赞
            if (operation.intValue() == 0) {
                // 点赞+1
                apComment.setLikes(apComment.getLikes() + 1);
                mongoTemplate.save(apComment);
                // 保存评论点赞信息
                apCommentLike = ApCommentLike.builder().authorId(user.getId()).commentId(apComment.getId())
                        .operation(dto.getOperation()).build();
                mongoTemplate.save(apCommentLike);
                //计算热点评论评论
                if (apComment.getLikes() >= 10 && apComment.getFlag() == 0) {
                    commentHotService.hotCommentExecutor(apComment);
                }
            } else {
                // 取消点赞
                apComment.setLikes(
                        apComment.getLikes() <= 0 ? 0 : apComment.getLikes() - 1);
                mongoTemplate.save(apComment);
                //删除点赞评论信息
                mongoTemplate.remove(Query.query(Criteria.
                        where("authorId").is(user.getId())
                        .and("commentId").is(apComment.getId())), ApCommentLike.class);
            }
        } finally {
            lock.unlock();
        }
        //4 数据返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("likes", apComment.getLikes());
        return ResponseResult.okResult(resultMap);
    }

    @Override
    public ResponseResult loadCommentList(CommentDTO dto) {
        //校验size
        Integer size = dto.getSize();
        if (size == null || size == 0) {
            size = 10;
        }
        //校验时间
        Date date = dto.getMinDate();
        if (dto.getMinDate() == null) {
            date = new Date();
        }
        List<ApComment> apCommentList = new ArrayList<>();
        if (dto.getIndex() == 1) {
            // 先查询热点评论集合  （最多5条） (条件: flag=1, 文章id, 点赞降序)
            List<ApComment> apComments = mongoTemplate.find(Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("flag").is(1))
                    .with(Sort.by(Sort.Direction.DESC, "likes")).limit(5), ApComment.class);
            apCommentList.addAll(apComments);
            // 新size = size - 热评数量
            size = size - apComments.size();
            // 查询第一页剩余普通评论 (条件: 文章id, flag=0, 时间降序, limit:新size)
            List<ApComment> generalComments = mongoTemplate.find(Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("flag").is(0))
                    .with(Sort.by(Sort.Direction.DESC, "createdTime")).limit(size), ApComment.class);
            // 合并 热点评论  普通评论   热点list.addAll(普通list)
            apCommentList.addAll(generalComments);
        }
        //不是第一页,查询普通评论
        Query query = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                .and("createdTime").lt(date)).with(Sort.by(Sort.Direction.DESC, "createdTime")).limit(size);
        List<ApComment> list = mongoTemplate.find(query, ApComment.class);

        apCommentList.addAll(list);
        apCommentList = apCommentList.stream().distinct().collect(Collectors.toList());
        //校验用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            //未登录直接返回评论列表
            return ResponseResult.okResult(apCommentList);
        }
        //查询当前评论列表的id集合
        List<String> ids = apCommentList.stream().map(ApComment::getId).collect(Collectors.toList());
        //用户点赞的数据集合
        List<ApCommentLike> apCommentLikes = mongoTemplate.find(Query.query(Criteria.where("commentId")
                .in(ids).and("authorId").is(user.getId())), ApCommentLike.class);
        //获取点赞数据的评论id
        List<String> commentIds = apCommentLikes.stream().map(ApCommentLike::getCommentId).collect(Collectors.toList());

        List<ApCommentVo> apCommentVos = apCommentList.stream().map(comment -> {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(comment, apCommentVo);
            //如果当前评论id在点赞记录中存在
            if (commentIds.contains(comment.getId())) {
                apCommentVo.setOperation((short) 0);
            }
            return apCommentVo;
        }).collect(Collectors.toList());
        return ResponseResult.okResult(apCommentVos);
    }
}